using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Serialization;
using virtuaPol.Model;
using virtuaPol.Util;

namespace virtuaPol.Main
{
    public class WorldLoader
    {
        private const int BUFFER_SIZE = 2048;

        public static bool save(ref CWorld world, string filename)
        {
            return save(ref world, filename, true);
        }

        public static bool save(ref CWorld world, string filename, bool compressed)
        {
            if (compressed)
                return saveGZip(ref world, filename);
            else
                return saveRaw(ref world, filename);
        }

        public static bool load(out CWorld world, string filename)
        {
            return load(out world, filename, true);
        }

        public static bool load(out CWorld world, string filename, bool compressed)
        {
            if (compressed)
                return loadGZip(out world, filename);
            else
                return loadRaw(out world, filename);
        }

        private static bool saveRaw(ref CWorld world, string filename)
        {
            FileStream fs = null;
            MemoryStream ms = null;
            try
            {
                ms = new MemoryStream();
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(CWorld));
                xmlSerializer.Serialize(ms, world);
                ms.Position = 0;
                fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None);
                byte[] buffer = new byte[BUFFER_SIZE];
                while (true)
                {
                    int bytesRead = ms.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break;
                    fs.Write(buffer, 0, bytesRead);
                }

                return true;
            }
            catch (Exception ex)
            {
                CLogger.LogError(ex);
                return false;
            }
            finally
            {
                if (ms != null) ms.Close();
            }
        }

        private static bool saveGZip(ref CWorld world, string filename)
        {
            FileStream fs = null;
            MemoryStream ms = null;
            GZipStream gs = null;
            try
            {
                ms = new MemoryStream();
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(CWorld));
                xmlSerializer.Serialize(ms, world);
                ms.Position = 0;
                fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None);
                gs = new GZipStream(fs, CompressionMode.Compress);
                byte[] buffer = new byte[BUFFER_SIZE];
                while (true)
                {
                    int bytesRead = ms.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break;
                    gs.Write(buffer, 0, bytesRead);
                }

                return true;
            }
            catch (Exception ex)
            {
                CLogger.LogError(ex);
                return false;
            }
            finally
            {
                if (ms != null) ms.Close();
                if (gs != null) gs.Close();
            }

        }

        private static bool loadRaw(out CWorld world, string filename)
        {
            FileStream fs = null;
            MemoryStream ms = null;
            try
            {
                fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
                ms = new MemoryStream();
                byte[] buffer = new byte[BUFFER_SIZE];
                while (true)
                {
                    int bytesRead = fs.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break;
                    ms.Write(buffer, 0, bytesRead);
                }
                // Reset stream position
                ms.Position = 0;
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(CWorld));
                world = (CWorld)xmlSerializer.Deserialize(ms);

                return true;
            }
            catch (Exception ex)
            {
                CLogger.LogError(ex);
                world = null;
                return false;
            }
            finally
            {
                if (fs != null) fs.Close();
                if (ms != null) ms.Close();
            }
        }

        private static bool loadGZip(out CWorld world, string filename)
        {
            FileStream fs = null;
            MemoryStream ms = null;
            GZipStream gs = null;
            try
            {
                fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
                ms = new MemoryStream();
                gs = new GZipStream(fs, CompressionMode.Decompress);
                byte[] buffer = new byte[BUFFER_SIZE];
                while (true)
                {
                    int bytesRead = gs.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break;
                    ms.Write(buffer, 0, bytesRead);
                }
                // Reset stream position
                ms.Position = 0;
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(CWorld));
                world = (CWorld)xmlSerializer.Deserialize(ms);

                return true;
            }
            catch (Exception ex)
            {
                CLogger.LogError(ex);
                world = null;
                return false;
            }
            finally
            {
                if (ms != null) ms.Close();
                if (gs != null) gs.Close();
            }
        }
    }
}
